//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _APPS_BUSH_PARSER_CTOKENIZER_H_
#define _APPS_BUSH_PARSER_CTOKENIZER_H_

#include <buola/buola.h>

#include <buola/zz/zsymbols.h>
#include <deque>
#include <map>

#include "enums.h"
#include "ctoken.h"

namespace buola { namespace bush {

class CTokenizer
{
public:
    enum EStatus
    {
        STATUS_OK=0,
        STATUS_DEDENT_ERROR=(1<<0),
        STATUS_STRING_ERROR=(1<<1),
        STATUS_STRING_EOI=(1<<2),
        STATUS_LINECONT_EOI=(1<<3)
    };

    DECLARE_FRIEND_ENUM_BITOPS(EStatus);
    
    typedef CToken::tIt tIt;
    
    CTokenizer();

    std::string GetTokenName(EToken pToken) {   return mTokenNames[pToken];}
    
private:
    void AddSimpleToken(EToken pToken,tIt &pI,std::vector<CToken> &pTokens);
    
    void TokenizeLineStart(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens,bool pFirstLine);
    void TokenizeSpace(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeOperator(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeString(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizePrefixedString(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeComment(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens,bool pAddToken=true);
    void TokenizeEncloser(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeDot(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeDigit(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeBackslash(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeDollar(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);
    void TokenizeWord(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);

public:
    ETokenizeResult Tokenize(tIt &pB,const tIt &pE,std::vector<CToken> &pTokens);

    void PrintTokens(TTokenIt pB,TTokenIt pE);

    int GetLastIndent()     {   return mIndentStack.empty()?0:mIndentStack.back();  }
    std::vector<int> GetIndentLevels()  {   return std::vector<int>(mIndentStack.begin(),mIndentStack.end());   }

    CTrie<wchar_t,EToken> &Keywords()     {   return mKeywords;   }
    CTrie<wchar_t,EToken> &Ops()          {   return mOps;   }

private:
    CTrie<wchar_t,EToken> mKeywords;
    CTrie<wchar_t,EToken> mOps;
    
    std::deque<wchar_t> mEncloserStack;
    std::deque<int> mIndentStack;

    std::map<EToken,std::string> mTokenNames;    

    EStatus mStatus;
};

//NOTE: some of the tokens returned by CTokenizer may be empty, that is, mB==mE. This will only happen for tokens of
//type INDENT, DEDENT and EOI.

/*namespace bush*/ } /*namespace buola*/ }

#endif
